/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       gpuprogram.h
 * Author:     karooolek
 * Created on: 2009-03-19
 *
 **********************************************************************************************************************/

#ifndef GPUPROGRAM_H_
#define GPUPROGRAM_H_

#include "texture.h"
#include "glee.h"
#include "../common.h"

namespace mGameEngine
{
namespace Graphics
{

/**
 * Program executed on GPU (Graphics Processing Unit)
 * written in GLSL (OpenGL Shading Language).
 * Various vertex and fragment shaders can be attached to achieve
 * a lot of amazing graphic effects.
 */
class GPUProgram
{
protected:
    /**
     * Active GPU program.
     */
    static uint _active;

    /**
     * GPU program object.
     */
    uint _program;

    /**
     * Vertex shader object.
     */
    uint _vertexShader;

    /**
     * Fragment shader object.
     */
    uint _fragmentShader;

    /**
     * Vertex shader source code.
     */
    String _vertexSource;

    /**
     * Fragment shader source code.
     */
    String _fragmentSource;

    /**
     * Is GPU program compiled.
     */
    bool _compiled;

    /**
     * GPU program compilation log.
     */
    String _compilationLog;

public:
    /**
     * Used fixed pipeline functionality.
     */
    static void useFixedPipeline();

    /**
     * Create empty GPU program.
     */
    GPUProgram();

    /**
     * Create GPU program with specified shaders source codes.
     * @param vertexSource vertex shader source code.
     * @param fragmentSource fragment shader source code.
     * @param compile compile program.
     */
    GPUProgram(const String &vertexSource, const String &fragmentSource, bool compile = false);

    /**
     * Destroy GPU program.
     */
    virtual ~GPUProgram();

    /**
     * Get vertex shader source code.
     * @return vertex shader source code.
     */
    const String &getVertexShaderSource() const
    {
        return _vertexSource;
    }

    /**
     * Set vertex shader source code.
     * @param vertexSource vertex shader source code.
     */
    void setVertexShaderSource(const String &vertexSource)
    {
        _vertexSource = vertexSource;
        _compiled = false;
    }

    /**
     * Get fragment shader source code.
     * @return fragment shader source code.
     */
    const String &getFragmentShaderSource() const
    {
        return _fragmentSource;
    }

    /**
     * Set fragment shader source code.
     * @param fragmentSource fragment shader source code.
     */
    void setFragmentShaderSource(const String &fragmentSource)
    {
        _fragmentSource = fragmentSource;
        _compiled = false;
    }

    /**
     * Check if GPU program is compiled.
     * @return true if GPU program is compiled, false otherwise.
     */
    bool isCompiled() const
    {
        return _compiled;
    }

    /**
     * Compile GPU program.
     * After that GPU program is ready to use.
     */
    void compile();

    /**
     * Get GPU progrm compilation log.
     * @return GPU program compilation log.
     */
    const String &getCompilationLog() const
    {
        return _compilationLog;
    }

    /**
     * Set GPU program uniform value.
     * @param name variable name.
     * @param a value to set.
     */
    virtual void setValue(const String &name, float a);

    /**
     * Set GPU program uniform value.
     * @param name variable name.
     * @param a value to set.
     */
    virtual void setValue(const String &name, int a);

    /**
     * Set GPU program uniform vector value.
     * @param name vector name.
     * @param v vector to set.
     */
    virtual void setVector(const String &name, const Vector2 &v);

    /**
     * Set GPU program uniform vector.
     * @param name vector name.
     * @param v vector to set.
     */
    virtual void setVector(const String &name, const Vector3 &v);

    /**
     * Set GPU program uniform vector.
     * @param name vector name.
     * @param v vector to set.
     */
    virtual void setVector(const String &name, const Vector4 &v);

    /**
     * Set GPU program uniform matrix.
     * @param name matrix name.
     * @param m matrix to set.
     */
    virtual void setMatrix(const String &name, const Matrix2x2 &m);

    /**
     * Set GPU program uniform matrix.
     * @param name matrix name.
     * @param m matrix to set.
     */
    virtual void setMatrix(const String &name, const Matrix3x3 &m);

    /**
     * Set GPU program uniform matrix.
     * @param name matrix name.
     * @param m matrix to set.
     */
    virtual void setMatrix(const String &name, const Matrix4x4 &m);

    /**
     * Set GPU program uniform texture.
     * @param name texture (sampler) name.
     * @param texture texture to set.
     * @param texUnit texture unit to use.
     */
    virtual void setTexture(const String &name,
                            const Texture *texture, uint8 texUnit);
    /**
     * Use GPU program.
     */
    void use() const;
};

}
}

#endif // GPUPROGRAM_H_
